package cn.hackcloud.netty.codec.marshalling;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class BookServer {
	public static void main(String[] args) throws Exception {
		new BookServer().bind();
	}

	public void bind() throws Exception {
		// NioEventLoopGroup是一个线程组，包含了一组NIO线程，专门用于网络事件的处理，实际上他们就是Reactor线程组
		// bossGroup仅接收客户端连接，不做复杂的逻辑处理，为了尽可能减少资源的占用，取值越小越好
		EventLoopGroup bossGroup = new NioEventLoopGroup(1);
		// 用于进行SocketChannel的网络读写
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			// 是Netty用于启动NIO服务端的辅助启动类，目的是降低服务端的开发复杂度
			ServerBootstrap b = new ServerBootstrap();
			// 配置NIO服务端
			b.group(bossGroup, workerGroup)
					// 指定使用NioServerSocketChannel产生一个Channel用来接收连接，他的功能对应于JDK
					// NIO类库中的ServerSocketChannel类。
					.channel(NioServerSocketChannel.class)
					// BACKLOG用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，
					// 用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1，
					// Java将使用默认值50。
					.option(ChannelOption.SO_BACKLOG, 1024).handler(new LoggingHandler(LogLevel.INFO))
					// 绑定I/O事件处理类，作用类似于Reactor模式中的Handler类，主要用于处理网络I/O事件
					.childHandler(new ChannelInitializer<SocketChannel>() {

						protected void initChannel(SocketChannel arg0) throws Exception {
							arg0.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
							arg0.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
							arg0.pipeline().addLast(new BookServerHandler());
						}
					});
			// 绑定端口，同步等待绑定操作完成，完成后返回一个ChannelFuture,用于异步操作的通知回调
			ChannelFuture f = b.bind(8080).sync();
			// 等待服务端监听端口关闭之后才退出main函数
			f.channel().closeFuture().sync();
		} finally {
			// 退出，释放线程池资源
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
		}
	}

}

class BookServerHandler extends ChannelHandlerAdapter {
	/**
	 * 接受客户端发送的消息
	 * 
	 * @param ctx
	 * @param msg
	 * @throws Exception
	 */
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		BookInfo bookInfo = (BookInfo) msg;
		System.out.println("Server receive: " + bookInfo.toString());
		BookInfo bookInfo1 = new BookInfo();
		bookInfo1.setId(bookInfo.getId());
		bookInfo1.setName("Server Netty Marshalling");
		bookInfo1.setType("book order succeed");
		ctx.writeAndFlush(bookInfo1);
	}

	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		// 将消息发送队列中的消息写入到SocketChannel中发送给对方
		ctx.flush();
	}

	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		// 当发生异常时释放资源
		ctx.close();
	}
}
